package cate.game.role.pvp.minecraft.po;

import cate.common.table.d.*;
import cate.common.table.pvp.minecraft.challenge_base.MinecraftChallengeBaseRow;
import cate.common.util.GameResult;
import cate.game.res.MixRes;
import cate.game.res.MixResAdder;
import cate.game.res.MixResConsumer;
import cate.game.res.MixResItem;
import cate.game.res.drop.DropConfigHelper;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.pvp.minecraft.msg.MinecraftChallengeInfoResp;
import cate.game.role.pvp.minecraft.msg.MinecraftChallengeWatchResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@NoteClass("矿洞争霸-挑战区")
public class MinecraftChallengePO extends RoleDependent {
    @NoteField("是否开启")
    public boolean active;
    @NoteField("主城等级")
    public int cityLevel;
    @NoteField(value = "上一次领取挂机收益的时间")
    public long lastHangGotTime;
    @NoteField(value = "上一次生成挂机收益的时间", detail = "实际用于结算的时间")
    public long lastBuildRewardTime;
    @NoteField(value = "之前观察时累计生成的基础奖励", detail = "前端可以只看不领取奖励")
    public MixRes baseRewardTemp;
    @JsonIgnore
    @NoteField(value = "未结算分钟数")
    public Map<Integer, Integer> remainMinutesMap;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (cityLevel <= 0) {
            cityLevel = 1;
        }
        if (baseRewardTemp == null) {
            baseRewardTemp = new MixRes();
        }
        if (remainMinutesMap == null) {
            remainMinutesMap = new HashMap<>();
        }
    }

    /**
     * 功能开启
     */
    public void onAfterOpen() {
        if (active) {
            return;
        }
        active = true;
        lastHangGotTime = System.currentTimeMillis();
        lastBuildRewardTime = System.currentTimeMillis();
        noticeUpdate();
    }

    /**
     * 获取基础配置
     */
    @JsonIgnore
    private MinecraftChallengeBaseRow getBaseRow() {
        return role.getGame().table.minecraft.challenge_base.get(cityLevel);
    }

    /**
     * 同步信息到前端
     */
    public void noticeUpdate() {
        role.sendNow(new MinecraftChallengeInfoResp(this));
    }

    /**
     * 领取或观察挂机奖励
     */
    public void receiveOrWatchHangReward(boolean watch) {
        if (!active) {
            return;
        }
        //最大挂机分钟数
        int max = getHangMaxTime();
        final long MIN = 60000; // 一分钟
        long now = System.currentTimeMillis();
        // 距离上次领取奖励经过的时间
        int getPastMinutes = (int) ((now - lastHangGotTime) / MIN);
        //超过最大挂机时间
        if (getPastMinutes > max) {
            getPastMinutes = max;
        }
        //已经结算过的时间
        int settleMiutes = (int) ((lastBuildRewardTime - lastHangGotTime) / MIN);
        //本次需要结算的分钟数
        int minutes = getPastMinutes - settleMiutes;
        if (minutes <= 0) {
            minutes = 0;
        }
        // 根据挂机时间计算收益
        calAndSendReward(minutes, watch);
    }

    /**
     * 计算并发送挂机奖励
     *
     * @param times 分钟数
     * @param watch 是否为预览
     */
    public void calAndSendReward(int times, boolean watch) {
        // 本次生成的挂机奖励
        MixRes baseReward = new MixRes();
        if (times == 0 && !watch && baseRewardTemp.isEmpty()) {
            role.getGame().notice.message(role, 310104, "满一分钟才能领奖励");
            return;
        }
        // 时间超过1分钟才开始计算
        if (times > 0) {
            // 主线挂机本生产出的资源
            baseReward = buildBaseReward(times);
            if (baseReward.items.isEmpty()) {
                role.getGame().notice.message(role, "此通关数尚无对应奖励");
                return;
            }
        }
        // 奖励要和之前的一起发
        baseReward.addList(buildRandomReward(times));
        baseRewardTemp.addList(baseReward);
        lastBuildRewardTime += 60000L * times;
        if (watch) {
            role.sendNow(new MinecraftChallengeWatchResp(baseRewardTemp));
        } else {
            new MixResAdder()
                    .setRes(baseRewardTemp)
                    .setOperation(GDOperation.MINECRAFT_CHALLENGE_HANG_REWARD)
                    .setDialogReward(true)
                    .setSendMailWhenFull(true)
                    .exe(role);
            baseRewardTemp.clear();
            lastHangGotTime = System.currentTimeMillis();
            lastBuildRewardTime = lastHangGotTime;
            noticeUpdate();
        }
    }

    /**
     * 计算基础挂机奖励
     *
     * @param times 分钟数
     * @return 挂机奖励
     */
    private MixRes buildBaseReward(int times) {
        return Optional.ofNullable(getBaseRow())
                .map(row -> new MixRes(row.hangResPerMinuteStr).multiply(times))
                .orElse(new MixRes());
    }

    /**
     * 计算随机挂机奖励
     *
     * @param times 分钟数
     * @return 挂机奖励
     */
    private MixRes buildRandomReward(int times) {
        MinecraftChallengeBaseRow baseRow = getBaseRow();
        if (baseRow == null) {
            return new MixRes();
        }
        MixRes res = new MixRes();
        baseRow.randomDropList.forEach(dropItem -> {
           int min = times + remainMinutesMap.getOrDefault(dropItem.dropId, 0);
           int count = min / dropItem.interval;
           int remain = min % dropItem.interval;
           for (int i = 0; i < count; i++) {
               if (dropItem.weight >= (int) (100 * Math.random())) {
                   res.addList(DropConfigHelper.getDropReward(role.getGame(), dropItem.dropId));
               }
           }
           if (remain > 0) {
               remainMinutesMap.put(dropItem.dropId, remain);
           } else {
               remainMinutesMap.remove(dropItem.dropId);
           }
        });
        return res;
    }

    /**
     * 获取最长挂机时长(min)
     */
    @JsonIgnore
    private int getHangMaxTime() {
        return Optional.ofNullable(getBaseRow()).map(row -> row.maxHangMinute).orElse(0);
    }

    /**
     * 升级主城
     */
    public EcResult<Void> levelUp() {
        EcResult<Void> r = new EcResult<>();
        int nextLevel = cityLevel + 1;
        MinecraftChallengeBaseRow nextRow = role.getGame().table.minecraft.challenge_base.get(nextLevel);
        if (nextRow == null) {
            return r.fail("已达到当前版本最高等级");
        }
        MixRes cost = new MixRes(nextRow.levelUpCostStr);
        if (cost.isEmpty()) {
            return r.fail("Error Cost!");
        }
        GameResult<MixResItem> r_cost = new MixResConsumer<MixResItem>().res(cost)
                .tips(true)
                .operation(GDOperation.MINECRAFT_CHALLENGE_LEVEL_UP_COST, nextLevel)
                .exe(role);
        if (!r_cost.ok()) {
            return r.fail(r_cost.code, r_cost.message);
        }
        cityLevel = nextLevel;
        role.getHistory().action.minecraftLevelUp(cityLevel);
        return r.success();
    }
}
